package com.mach.platform.sprider.getter;

import com.mach.platform.sprider.dev.ByteUtil;
import com.mach.platform.sprider.dev.DataHelper;
import com.mach.platform.sprider.dev.TcpWorker;
import com.mach.platform.sprider.dev.UU;
import com.mach.platform.util.SqlHelper;
import com.mach.platform.util.U;
import lombok.extern.slf4j.Slf4j;


import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.*;

@Slf4j
public class GeneralModbusDev implements Runnable, GeneralDev{

    protected  Map<String, Object> devInfoMap;
    protected final SqlHelper sqlHelper;
    protected final DataLogService dataLogService;
    protected String commAddr;
    protected String ip;
    protected Integer port;
    protected Integer busId;
    protected Integer devId;
    protected DataHelper dh;
    protected Integer devTypeId;
    protected Map<Object, Object> addrMap;
    private boolean isRun = false;
    private String prol = null;
    private boolean isTcp = false;
    public TcpWorker tcpWorker;

    //采集频率
    private static final Integer COLLECT_FRE = 10;

    public GeneralModbusDev(Map<String, Object> devInfoMap, SqlHelper sqlHelper, DataLogService dataLogService) throws SQLException {

        this.devInfoMap = devInfoMap;

        this.sqlHelper = sqlHelper;

        this.dataLogService = dataLogService;

        this.init();

    }

    protected void init() throws SQLException {

        this.commAddr = (String)this.devInfoMap.get("commAddr");

        this.devId = Integer.parseInt(this.devInfoMap.get("devId").toString());

        this.devTypeId = (Integer)this.devInfoMap.get("devTypeId");

        this.initCommAddr();

        this.addrMap = sqlHelper.getMapFrTable("name", "valueAddr",
                "select name, value_addr valueAddr " +
                        " from iot_coll_items colls " +
                        " where colls.dev_type_id=" + this.devTypeId);

        DataHelper dh = new DataHelper(this.ip,this.port, this.busId);
        this.dh = dh;
        TcpWorker tk=new TcpWorker(this.ip,this.port);
        this.tcpWorker=tk;

        this.prol = (String)this.devInfoMap.get("prol");
        if("GeneralModbusRTU".equals(prol)){
            this.isTcp = false;
        }else
        if ("GeneralModbusTCP".equals(prol)){
            this.isTcp = true;
        }


    }

    protected void initCommAddr() {
        if(null == this.commAddr)return;

        String[] addrStrs = this.commAddr.split(":");

        if(addrStrs.length < 3){
            this.isRun=true;
            return;
        }

        this.ip = addrStrs[0];
        this.port = Integer.parseInt(addrStrs[1]);
        this.busId = Integer.parseInt(addrStrs[2]);

    }

    @Override
    public void run(){
        if(isRun){
            return;
        }

        this.isRun = true;

        try {
            while(true){

                this.pick();

                //UU.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.isRun = false;
        }
    }


    protected void pick() {
//        "select dev.id devId, dev.name name,type.prol prol,  dev.dev_type_id devTypeId,\n" +
//                " coll.id collId, coll.name collName, coll.value_addr collAddr,\n " +
//                " dev.comm_addr commAddr,\n" +
//                " coll.data_len collLen, coll.data_type collDataType,\n"；

        Map<Integer, Object> collMap = (Map<Integer, Object>) this.devInfoMap.get("coll");

        Set<Map.Entry<Integer, Object>> collEntrys = collMap.entrySet();

        List<Integer> collAddrList = new ArrayList<>(500);

        for(Map.Entry<Integer, Object> collEntry : collEntrys){
            Map<String, Object> coll = (Map<String, Object>) collEntry.getValue();

            Integer devId = Integer.parseInt(this.devInfoMap.get("devId").toString());
            String collName = (String)coll.get("collName");
            BigDecimal collAddr = (BigDecimal)coll.get("collAddr");

            String collDataType = (String)coll.get("collDataType");
;

            Object result = null;

//            log.info("collName"+ collName);

            try {
                byte[] databuf = null;
                if( "运行时间".equals(collName) && collDataType.equals("vir")){
                    Double oldValue = DataCenter.curDevDataTypeValue(this.devId,collName);
                    if(oldValue == null)oldValue = 0.0;
                    Double resultDb = 0.3 + oldValue;
                    result = resultDb;
                }else{
                    result = this.getValueByColl(coll);
                }

            }catch (Exception e){
                e.printStackTrace();
                System.err.println("error msg:" + e.getLocalizedMessage() + " devId=" + this.devId + "");
                result = null;
            }
            System.out.println(collName + "->> result :" + result);
            if(result != null){
                MainWork.addResult(devInfoMap, coll, result);
//                UU.sleep(60*1000);
             }
//            collAddrList.add(collAddr.intValue());
        }
//        Collections.sort(collAddrList);
//
//        List<List<Integer>> lists = this.pickList(collAddrList, COLLECT_FRE);
//        for (List<Integer> l : lists){
//            try {
//                this.getValueByColl(l, collEntrys);
//            }catch (Exception e){
//                e.printStackTrace();
//            }
//        }

    }

    /**
     *
     * @param list 需要分割的数组
     * @param register 寄存器数
     */
    private List<List<Integer>> pickList(List<Integer> list, int register) {
        int temp = register;
        List<Integer> arrayList = new ArrayList<>();
        List<List<Integer>> lists = new ArrayList<>();
        boolean flag = false;
        while (!flag){
            for (int j = 0; j < list.size(); j++){
                if (list.get(j) >= temp - register && list.get(j) < temp){
                    arrayList.add(list.get(j));
                }
            }
            temp = temp + register;
            if (arrayList.size() != 0){
                lists.add(arrayList);
            }
            for (Integer integer : arrayList){
                if (Objects.equals(integer, list.get(list.size() - 1))){
                    flag = true;
                }
            }
            arrayList = new ArrayList<>();
        }
        return lists;
    }

    /**
     *
     * @param list 地址区间
     * @param collEntrys 某个地址
     * @throws IOException
     */
    private void getValueByColl(List<Integer> list, Set<Map.Entry<Integer, Object>> collEntrys) throws IOException {
        Object result = null;

        byte[] databuf = null;

        byte[] orgData  = null;

        orgData = this.dh.getDataRtu(list.get(0), COLLECT_FRE);
        if(orgData == null || orgData.length <1)return ;
        //循环区间地址码，对应数据存入数据库
        for (int i = 0; i < list.size(); i++){
            Integer devId = 0;
            Integer collLen = 0;
            String collDataType = null;
            String collName = null;
            String collUnit = null;
            //根据地址码取出对应的设备数据
            Map<String, Object> coll = null;
            for(Map.Entry<Integer, Object> collEntry : collEntrys){
                coll = (Map<String, Object>) collEntry.getValue();
                if (list.get(i)==(((BigDecimal)coll.get("collAddr")).intValue())){
                    devId = (Integer)this.devInfoMap.get("devId");
                    if (!"运行状态".equals(coll.get("collName"))){
                        collLen = (Integer)coll.get("collLen");
                        collDataType = (String)coll.get("collDataType");
                        collUnit = (String)coll.get("collUnit");
                        collName = (String)coll.get("collName");
                    }
                }
            }
            //获取开始截取的位置
            int ix = (list.get(i)-list.get(0))*2;
            databuf = ByteUtil.subData(orgData,3+ix,collLen.intValue());

            result = UU.bytes2Value(collDataType, databuf);
            if(U.numInTang(-99999,99999999, result)){

            }else{
                result = null;
            }

            if(result != null && !"运行状态".equals(collName)){
                MainWork.addResult(devInfoMap, coll, result);
            }

        }

    }

    public void start() {

        if(!this.isRun){
            startCnt++;
            U.cachedThreadPool.execute(this);
        }
    }
    private int startCnt = 0;



    @Override
    public void cmd(Integer cmdId,String cmd, String param) {
        throw new RuntimeException("Un Support...");
    }

    @Override
    public void updateDevInfo(Map<String, Object> devInfo) {
        this.devInfoMap = devInfo;
    }

    @Override
    public Object getValueByColl(Map<String, Object> coll) throws IOException {
        Object result = null;

        String prol = (String)this.devInfoMap.get("prol");
        String collName = (String)coll.get("collName");
        BigDecimal collAddr = (BigDecimal)coll.get("collAddr");
        Integer collLen = (Integer)coll.get("collLen");
        Integer cmdCode = (Integer)coll.get("collFunCode");
        if(cmdCode == null) cmdCode = 3;
        String collDataType = (String)coll.get("collDataType");
        String collUnit = (String)coll.get("collUnit");
        Integer collSaverNum = (Integer)coll.get("collSaverNum");
        Integer waitTime=(Integer) coll.get("collWaitTime");
        if(waitTime==null) waitTime=500;

        if (collSaverNum == null || collSaverNum == 0){
            collSaverNum = 3;
        }

        byte[] databuf = null;

        byte[] orgData  = null;

        this.tcpWorker.setSoTimeOutValue(waitTime);

        if ( this.isTcp ){
            orgData = this.dh.getDataTcp(collAddr.intValue(), collSaverNum, cmdCode);
            if(orgData == null || orgData.length <1)return null;;
            int len = orgData[8];
//            databuf = ByteUtil.subData(orgData,9,collLen.intValue());
            databuf = ByteUtil.subData(orgData,9,len);
        }else{
            orgData = this.dh.getDataRtu(collAddr.intValue(), collSaverNum, cmdCode);   //  结果数组
            // crc校验
            boolean checkResult = checkCRC(orgData);
            if (!checkResult){
                return null;
            }
            if(orgData == null || orgData.length <1)return null;
            databuf = ByteUtil.subData(orgData,3,collLen.intValue());
        }

        result = UU.bytes2Value(collDataType, databuf);

        if(U.numInTang(-99999,99999999, result)){

        }else{
            result = null;
        }

        return result;
    }

    /**
     * CRC校验
     * @param orgData
     * @return
     */
    private boolean checkCRC(byte[] orgData) {
        // CRC数据校验
        byte[] checkData = ByteUtil.subData(orgData, 0, orgData.length - 2); // 截取resultData前面需要校验的数据
        byte[] crcData = ByteUtil.subData(orgData, orgData.length - 2, 2); // 最后两位的CRC数据
        boolean crcCheck = Arrays.equals(UU.getCrc16Btye(checkData), crcData); // 进行CRC数据校验，是否相等
        return crcCheck;
    }

    @Override
    public Object getValueByCollName(String collName) throws IOException {
        Object result = null;

        if(collName == null)return null;

        Map<String, Object> coll = this.getCollByName(collName);

        if(coll == null)return null;

        result = this.getValueByColl(coll);

        return result;
    }

    @Override
    public Map<String, Object> getCollByName(String collName) {

        Map<Integer, Object> collMap = (Map<Integer, Object>) this.devInfoMap.get("coll");

        Set<Map.Entry<Integer, Object>> collEntrys = collMap.entrySet();

        Map<String, Object> coll = null;
        for(Map.Entry<Integer, Object> collEntry : collEntrys){
            Map<String, Object> collTmp = (Map<String, Object>) collEntry.getValue();


            String collNameFrObj = (String)collTmp.get("collName");

            if(collName.equals(collNameFrObj)){
                coll = collTmp;
                break;
            }
        }
        return coll;
    }

    @Override
    public Integer getDevId() {
        return this.devId;
    }
}

